/**
 * @file pkgman.go
 * @name 包管理器
 * @desc 实现包信息的存储和检索功能
 * @version 0.1
 */

package pkgman

import (
	"archive/tar"
	"compress/gzip"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"nest/internal/pkgerrors"
	"nest/internal/utils/loading"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// 包管理器
type PackageManager struct {
	config        Config
	cacheDir      string
	installDir    string // 安装目录
	api           API    // API接口
	db            *sql.DB
	httpClient    *http.Client
	resolvedDeps  map[string]ResolvedDependency // 已解析的依赖
	availablePkgs map[string][]string           // 包名 -> 可用版本列表
	metadataCache map[string]PackageMetadata    // 缓存包元数据
}

// 配置结构
type Config struct {
	IndexURL string `json:"index_url"`
	//缓存目录
	CacheDir string `json:"cache_dir"`
	// 安装目录
	InstallDir    string `json:"install_dir"`
	Concurrency   int    `json:"concurrency"`
	Timeout       int    `json:"timeout"`
	VerifySSL     bool   `json:"verify_ssl"`
	Verbose       bool   `json:"verbose"`
	Debug         bool   `json:"debug"`
	DefaultBranch string `json:"default_branch"`
}

// api接口
type API struct {
	PkgVersion string // 包的可用版本
	PkgMeta    string // 包元数据
}

// 新建元数据管理器
func NewPackageManager(configPath string) (*PackageManager, error) {
	// 加载配置
	config, err := loadConfig(configPath)
	if err != nil {
		return nil, fmt.Errorf("加载配置失败: %v", err)
	}

	// 创建必要的目录
	for _, dir := range []string{config.CacheDir, config.InstallDir} {
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				return nil, fmt.Errorf("创建目录失败: %v", err)
			}
		}
	}

	// 打开数据库
	dbPath := filepath.Join(config.CacheDir, "packages.db")
	// 打开或创建数据库
	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return nil, fmt.Errorf("打开数据库失败: %v", err)
	}

	// 初始化表结构
	if err := initDB(db); err != nil {
		return nil, fmt.Errorf("初始化数据库失败: %v", err)
	}

	// 创建 HTTP 客户端
	httpClient := &http.Client{
		Timeout: time.Duration(config.Timeout) * time.Second,
	}

	return &PackageManager{
		config:     config,
		cacheDir:   config.CacheDir,
		installDir: config.InstallDir,
		api: API{
			PkgVersion: "http://local.nest.cn/api/package/version", // 包的可用版本
			PkgMeta:    "http://local.nest.cn/api/package/meta",    // 包元数据
		},
		db:            db,
		httpClient:    httpClient,
		resolvedDeps:  make(map[string]ResolvedDependency),
		availablePkgs: make(map[string][]string),
		metadataCache: make(map[string]PackageMetadata),
	}, nil
}

// 加载配置文件
func loadConfig(path string) (Config, error) {
	homedir, err := os.UserHomeDir()
	if err != nil {
		fmt.Println("获取用户主目录失败:", err)
		os.Exit(1)
	}
	// 默认配置
	config := Config{
		IndexURL:      "http://local.nest.cn",
		CacheDir:      filepath.Join(homedir, ".nest", "cache"),
		InstallDir:    filepath.Join(homedir, ".nest", "packages"),
		Concurrency:   5,
		Timeout:       30,
		VerifySSL:     true,
		Verbose:       false,
		Debug:         false,
		DefaultBranch: "master",
	}

	// 如果配置文件存在，则加载
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		data, err := os.ReadFile(path)
		if err != nil {
			return config, fmt.Errorf("读取配置文件失败: %v", err)
		}

		if err := json.Unmarshal(data, &config); err != nil {
			return config, fmt.Errorf("解析配置文件失败: %v", err)
		}
	}

	return config, nil
}

// 初始化数据库
func initDB(db *sql.DB) error {
	// 创建包信息表
	_, err := db.Exec(`
		CREATE TABLE IF NOT EXISTS packages (
			name TEXT PRIMARY KEY,
			versions JSON NOT NULL,
			updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
		)
	`)
	if err != nil {
		return err
	}

	// 创建已安装包表
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS installed_packages (
			name TEXT,
			version TEXT,
			path TEXT,
			installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			PRIMARY KEY (name, version)
		)
	`)
	if err != nil {
		return err
	}

	return nil
}

// 安装包
func (pm *PackageManager) InstallPackage(packageName, version string) (string, error) {
	l := loading.New()
	l.Start()
	defer l.Stop()              // 确保函数返回时停止动画
	time.Sleep(1 * time.Second) // 模拟安装过程
	// 检查是否已安装
	if pm.IsPackageInstalled(packageName, version) {
		// 如果已安装，直接返回成功信息
		return "", pkgerrors.Info(fmt.Sprintf("%s 已安装\n", packageName))
	}

	// 解析依赖
	dependencies, err := pm.ResolveDependencies(packageName, version)
	if err != nil {
		return "", pkgerrors.Error("解析依赖失败", err)
	}
	l.Stop()
	// 打印依赖树
	fmt.Println("依赖树:")
	for _, dep := range dependencies {
		fmt.Printf("- %s@%s\n", dep.Name, dep.Version)
	}

	// 创建并发控制
	semaphore := make(chan struct{}, pm.config.Concurrency)
	var wg sync.WaitGroup
	errs := make(chan error, len(dependencies))

	// 安装所有依赖
	for _, dep := range dependencies {
		wg.Add(1)
		semaphore <- struct{}{} // 获取令牌

		go func(d ResolvedDependency) {
			defer wg.Done()
			defer func() { <-semaphore }() // 释放令牌

			metadata, err := pm.GetPackageMetadata(d.Name, d.Version)
			if err != nil {
				errs <- fmt.Errorf("获取 %s@%s 元数据失败: %v", d.Name, d.Version, err)
				return
			}
			// 下载包
			packagePath, err := pm.DownloadPackage(metadata)
			if err != nil {
				errs <- fmt.Errorf("下载 %s@%s 失败: %v", d.Name, d.Version, err)
				return
			}

			// 安装包
			if err := pm.installPackageFromFile(packagePath, metadata); err != nil {
				errs <- fmt.Errorf("安装 %s@%s 失败: %v", d.Name, d.Version, err)
				return
			}

			fmt.Printf("成功安装 %s@%s\n", d.Name, d.Version)
		}(dep)
	}

	// 等待所有 goroutine 完成
	wg.Wait()
	close(errs)

	// 检查是否有错误
	for err := range errs {
		if err != nil {
			return "", err
		}
	}

	return "", nil
}

// 从文件安装包
func (pm *PackageManager) installPackageFromFile(packagePath string, metadata PackageMetadata) error {
	// 创建安装目录
	installPath := filepath.Join(pm.installDir, metadata.Name, metadata.Version)
	if _, err := os.Stat(installPath); os.IsNotExist(err) {
		if err := os.MkdirAll(installPath, 0755); err != nil {
			return fmt.Errorf("创建安装目录失败: %v", err)
		}
	}
	// 解压包
	file, err := os.Open(packagePath)
	if err != nil {
		return fmt.Errorf("打开包文件失败: %v", err)
	}
	defer file.Close()

	gzr, err := gzip.NewReader(file)
	// zr, err := zip.OpenReader(file.Name())
	if err != nil {
		return fmt.Errorf("解压失败: %v", err)
	}
	defer gzr.Close()

	tr := tar.NewReader(gzr)

	// 遍历 tar 文件内容
	for {
		header, err := tr.Next()
		if err == io.EOF {
			break // 结束
		}
		if err != nil {
			return fmt.Errorf("读取 tar 文件失败: %v", err)
		}

		// 构建目标路径
		// 跳过顶层目录
		fileName := header.Name
		if strings.Contains(fileName, "/") {
			fileName = strings.SplitN(fileName, "/", 2)[1]
		}
		if fileName == "" {
			continue
		}

		target := filepath.Join(installPath, fileName)

		// 处理目录
		if header.Typeflag == tar.TypeDir {
			if _, err := os.Stat(target); os.IsNotExist(err) {
				if err := os.MkdirAll(target, 0755); err != nil {
					return fmt.Errorf("创建目录失败: %v", err)
				}
			}
			continue
		}

		// 处理文件
		if header.Typeflag == tar.TypeReg {
			// 创建父目录
			dir := filepath.Dir(target)
			if _, err := os.Stat(dir); os.IsNotExist(err) {
				if err := os.MkdirAll(dir, 0755); err != nil {
					return fmt.Errorf("创建目录失败: %v", err)
				}
			}

			// 创建文件
			file, err := os.Create(target)
			if err != nil {
				return fmt.Errorf("创建文件失败: %v", err)
			}

			// 设置文件权限
			if err := os.Chmod(target, os.FileMode(header.Mode)); err != nil {
				file.Close()
				return fmt.Errorf("设置文件权限失败: %v", err)
			}

			// 写入文件内容
			if _, err := io.Copy(file, tr); err != nil {
				file.Close()
				return fmt.Errorf("写入文件内容失败: %v", err)
			}

			file.Close()
		}
	}

	// 记录安装信息
	_, err = pm.db.Exec(`
		INSERT INTO installed_packages (name, version, path) VALUES (?, ?, ?)
	`, metadata.Name, metadata.Version, installPath)
	if err != nil {
		return fmt.Errorf("记录安装信息失败: %v", err)
	}

	return nil
}

// 检查包是否已安装
func (m *PackageManager) IsPackageInstalled(packageName, version string) bool {
	var count int
	err := m.db.QueryRow(`SELECT COUNT(*) FROM installed_packages WHERE name = ? or version = ?`, packageName, version).Scan(&count)
	return err == nil && count > 0
}

// 卸载包
func (pm *PackageManager) UninstallPackage(packageName, version string) (string, error) {
	l := loading.New()
	l.Start()
	defer l.Stop() // 确保函数返回时停止动画
	// 检查是否已安装
	if !pm.IsPackageInstalled(packageName, version) {
		return "", pkgerrors.Info(fmt.Sprintf("%s 未安装", packageName))
	}

	// 获取安装路径
	var installPath string
	err := pm.db.QueryRow(`SELECT path FROM installed_packages WHERE name = ? AND version = ?`, packageName, version).Scan(&installPath)

	if err != nil {
		// return "", fmt.Errorf("查询安装路径失败: %v", err)
		return "", pkgerrors.Error("查询安装路径失败", err)
	}

	// 删除安装目录
	if err := os.RemoveAll(installPath); err != nil {
		return "", pkgerrors.Error("删除安装目录失败", err)
	}

	// 从数据库中删除记录
	_, err = pm.db.Exec(`DELETE FROM installed_packages WHERE name = ? AND version = ?`, packageName, version)

	if err != nil {
		return "", pkgerrors.Error("删除安装记录失败", err)
	}

	return fmt.Sprintf("%s@%s 卸载成功\n", packageName, version), nil
}

// 列出已安装的包
func (pm *PackageManager) ListInstalledPackages() ([]ResolvedDependency, error) {
	rows, err := pm.db.Query(`
		SELECT name, version, path FROM installed_packages ORDER BY name, version
	`)

	if err != nil {
		return nil, pkgerrors.Error("查询已安装包失败", err)
	}
	defer rows.Close()

	var packages []ResolvedDependency
	for rows.Next() {
		var dep ResolvedDependency
		if err := rows.Scan(&dep.Name, &dep.Version, &dep.Path); err != nil {
			return nil, fmt.Errorf("扫描行失败: %v", err)
		}
		packages = append(packages, dep)
	}

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("遍历结果集失败: %v", err)
	}

	return packages, nil
}

// 关闭数据库连接
func (m *PackageManager) Close() error {
	return m.db.Close()
}

func (pm *PackageManager) ClearCache(name, version string) error {
	// 构建缓存路径
	// cachePath := filepath.Join(pm.cacheDir, "packages", fmt.Sprintf("%s-%s.egg", name, version))
	// 检查文件是否存在
	return nil
}
